package active

import (
	"server/game/handle/battle"
	"server/share/config"
	"server/share/protoc"

	"github.com/hwcer/cosgo/registry"
	"github.com/hwcer/cosgo/times"
	"github.com/hwcer/cosgo/utils"
	"github.com/hwcer/yyds/context"
	"github.com/hwcer/yyds/errors"
	"github.com/hwcer/yyds/players/player"
)

//梦境崩塌 BOSS战

func init() {
	Register(&ActStage{})
}

type ActStageResult struct {
	Score int32 `json:"s" bson:"s"` //得分
	Times int32 `json:"t" bson:"t"` //最快通关时间
}

type ActStage struct {
	Index  int32                     `json:"index" bson:"index"`   //当前第几个关卡，用来重置词条，如果当前index 和实际开放的序号不一致，必须先更新词条
	Daily  int64                     `json:"daily" bson:"daily"`   //上次领取结算奖励时间，用来判断一天只能领一次
	Result map[int32]*ActStageResult `json:"result" bson:"result"` //actStage.StageId -> ActStageResult
	Skills map[int32]int32           `json:"skills" bson:"skills"` //当前词条->词条等级 ,每个BOSS 选择一次
	Reward map[int32]int32           `json:"reward" bson:"reward"` //积分奖励,actStage.StageId --> 当前领过的最大的那个序号
}

func (this *ActStage) Caller(node *registry.Node, handle *context.Context) interface{} {
	f := node.Method().(func(*ActStage, *context.Context) interface{})
	return f(this, handle)
}

/**
 * @name startBattle
 * @param int id 活动ID
 * @param int key 关卡ID,actStage.id
 * 开始战斗
 */

func (this *ActStage) StartBattle(c *context.Context) interface{} {
	id := c.GetInt32("id")
	key := c.GetInt32("key")
	if key <= 0 {
		return errors.ErrArgEmpty
	}
	_, r, err := Verify(c.Player, id, config.Data.ActiveMod.ActStage, 1)
	if err != nil {
		return err
	}

	group := r.GetArgs()[0]

	att := &ActStage{}
	if err = r.Active.Unmarshal(att); err != nil {
		return err
	}
	//检查BOSSId
	index := this.GetIndex(c.Player, r.Cycle, group)
	if index <= 0 {
		return c.Errorf(0, "active config error")
	}
	if att.Index != index {
		return c.Errorf(0, "请先更新词条")
	}

	actStage := this.GetActStage(group, index)
	if actStage == nil {
		return c.Errorf(0, "actStage not found")
	}
	if actStage.Id != key {
		return c.Errorf(0, "actStage id mismatch")
	}

	mw := &battle.Middleware{}
	mw.Create(c.Player, battle.MiddlewareTypeActStage, key, c.Unix())
	return true
}

type ActStageBattleData struct {
	Win  int32 `json:"win"`
	Time int32 `json:"time"` //通关时间 (MS) 可能是 MS吧
}

type ActStageBattleResult struct {
	Id   int32              `json:"id"`
	Key  int32              `json:"key"`
	Data ActStageBattleData `json:"data"`
}

/**
 * @name endBattle
 * @param int id 活动ID
 * @param int key actStage.id
 * @param json data 通关数据
 * 结算战斗
 */
func (this *ActStage) EndBattle(c *context.Context) interface{} {
	args := ActStageBattleResult{}
	if err := c.Bind(&args); err != nil {
		return err
	}
	if args.Key <= 0 {
		return errors.ErrArgEmpty
	}

	handle, r, err := Verify(c.Player, args.Id, config.Data.ActiveMod.ActStage, 1)
	if err != nil {
		return err
	}
	group := r.GetArgs()[0]

	mw := &battle.Middleware{}
	if !mw.Verify(c.Player, battle.MiddlewareTypeActStage, args.Key) {
		return c.Error("battle error")
	}
	if args.Data.Win == 0 {
		return false //战斗失败
	}

	actStage := config.Data.ActStage[args.Key]
	if actStage == nil {
		return c.Errorf(0, "actStage not found")
	}
	if actStage.Group != group {
		return c.Errorf(0, "actStage group mismatch")
	}

	index := this.GetIndex(c.Player, r.Cycle, actStage.Group)
	if actStage.Index != index {
		return c.Errorf(0, "actStage index mismatch")
	}

	att := &ActStage{}
	if err = r.Active.Unmarshal(att); err != nil {
		return err
	}
	if att.Index != actStage.Index {
		return c.Errorf(0, "actStage index mismatch")
	}
	if att.Result == nil {
		att.Result = map[int32]*ActStageResult{}
	}
	boss := actStage.StageID
	result := att.Result[boss]
	if result == nil {
		result = &ActStageResult{}
		att.Result[boss] = result
	}

	score := actStage.Score
	for k, v := range att.Skills {
		if sk := this.GetActStageSkill(k, v); sk != nil {
			score += sk.EntryScore
		}
	}

	c.Player.Emit(config.Data.Events.ActBossChallenge, 1)
	if score > result.Score {
		result.Score = score
		result.Times = args.Data.Time
	}
	c.Player.Emit(config.Data.Events.ActScore, score)
	//if result.Times == 0 || args.Data.Time < result.Times {
	//	result.Times = args.Data.Time
	//}

	//首次奖励
	today := times.New(c.Now()).Daily(0).Now().Unix()
	if att.Daily < today {
		att.Daily = c.Unix()
		c.Player.AddItems(actStage.Reward)
	}

	handle.SetAttach(r.Active.OID, att)

	return nil
}

/**
 * @name UpdateSkill
 * @param string id 活动ID
 * @param map[int32]int32 skills  actStageSkill.skill-> 词条等级  (允许继承时未解锁的也可以选择)
 * 更新词条
 */
func (this *ActStage) UpdateSkill(c *context.Context) interface{} {
	args := struct {
		Id     int32           `json:"id" bson:"id"`
		Skills map[int32]int32 `json:"skills" bson:"skills"`
	}{
		Skills: make(map[int32]int32),
	}
	if err := c.Bind(&args); err != nil {
		return err
	}
	handle, r, err := Verify(c.Player, args.Id, config.Data.ActiveMod.ActStage, 1)
	if err != nil {
		return err
	}

	group := r.GetArgs()[0]
	att := &ActStage{}
	if err = r.Active.Unmarshal(att); err != nil {
		return err
	}

	actStageGroup := config.Data.ActStageGroup[group]
	if actStageGroup == nil {
		return c.Errorf(0, "actStage group not found")
	}

	inherit := make(map[int32]int32)
	if actStageGroup.Inherit > 0 {
		inherit = att.Skills //允许继承
	}

	index := this.GetIndex(c.Player, r.Cycle, group)
	if index <= 0 {
		return c.Errorf(0, "active config error")
	}
	actStage := this.GetActStage(group, index)
	if actStage == nil {
		return c.Errorf(0, "actStage not found")
	}
	boss := actStage.StageID

	cs := make(map[int32]struct{})
	for _, v := range actStage.Skills {
		cs[v] = struct{}{}
	}

	var score int32 = 0
	if v := att.Result[boss]; v != nil {
		score = v.Score
	}

	skills := make(map[int32]int32)
	for k, v := range args.Skills {
		if _, ok := cs[k]; !ok {
			return c.Errorf(0, "skills not exist:%d", k)
		}
		ass := this.GetActStageSkill(k, v)
		if ass == nil {
			return c.Errorf(0, "actStage skill not found")
		}
		if lv := inherit[k]; score >= ass.Score || lv >= v {
			skills[k] = v
		} else {
			return c.Errorf(0, "actStage skill locked")
		}

	}

	//SAVE
	att.Index = index
	att.Skills = skills
	handle.SetAttach(r.Active.OID, att)
	return nil
}

/**
 * @name Submit
 * @param int id 活动ID
 * @param int key actStage.StageID
 * 一键领取积分奖励
 */
func (this *ActStage) Submit(c *context.Context) interface{} {
	id := c.GetInt32("id")
	key := c.GetInt32("key")
	handle, r, err := Verify(c.Player, id, config.Data.ActiveMod.ActStage, 1)
	if err != nil {
		return err
	}

	att := &ActStage{}
	if err = r.Active.Unmarshal(att); err != nil {
		return err
	}
	var score int32 = 0
	if v := att.Result[key]; v != nil {
		score = v.Score
	}
	///
	if att.Reward == nil {
		att.Reward = map[int32]int32{}
	}
	i := att.Reward[key] + 1
	var save bool
	for {
		actStageReward := this.GetActStageReward(key, i)
		if actStageReward == nil || actStageReward.Score > score {
			break
		}
		att.Reward[key] = i
		c.Player.AddItems(actStageReward.Reward)
		i += 1
		save = true
	}
	if !save {
		return false
	}
	handle.SetAttach(r.Active.OID, att)
	return true
}

func (this *ActStage) GetIndex(p *player.Player, c *times.Cycle, group int32) int32 {
	actStageGroup := config.Data.ActStageGroup[group]
	if actStageGroup == nil {
		return 0
	}

	s, _ := c.Start()
	b := s.Now().Unix()
	now := p.Unix()
	if now < b {
		return 0
	}
	i := int32(utils.Ceil(now-b, 86400))
	r := utils.Ceil(i, actStageGroup.RotateTeam)
	if r > 99 {
		r = 0
	}
	return r
}

func (this *ActStage) GetActStage(group, index int32) *protoc.ActStage {
	k := group*100 + index
	return config.Data.ActStage[k]
}

func (this *ActStage) GetActStageSkill(skill, lv int32) *protoc.ActStageSkill {
	k := skill*100 + lv
	return config.Data.ActStageSkill[k]
}

func (this *ActStage) GetActStageReward(stageId, index int32) *protoc.ActStageReward {
	k := stageId*100 + index
	return config.Data.ActStageReward[k]
}
